﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using tea.Controllers;
using tea.DB;
using tea.Models;
using Util;

namespace tea.BL
{
    public class BL사용자
    {
        // 역할
        public const string USER = "USER";
        public const string STAFF = "STAFF";
        public const string ADMIN = "ADMIN";
        public const string ADMIN_OR_STAFF = "ADMIN, STAFF";
        public const string GUEST = "GUEST";
        public static string[] 역할목록 = { ADMIN, STAFF, USER, GUEST };

        private const string 임시비밀번호 = "!@#$";
        private const string KEY_CURRENTUSER = "KEY_CURRENTUSER";
        private const string KEY_CURRENTUSER_ROLES = "KEY_CURRENTUSER_ROLES";
        private static 사용자 손님 = new 사용자 { ID = 0, 로그인ID = "손님", 이름 = "손님" };

        public const int 검색_없음 = 0;
        public const int 검색_이름 = 1;
        public const int 검색_로그인ID = 2;

        public const int 사용자분류_전체 = 0;
        public static List<SelectListItemModel> 사용자분류 = new List<SelectListItemModel> { 
            new SelectListItemModel(0, "전체"),
            new SelectListItemModel(1, "Staff"),
            new SelectListItemModel(2, "Admin")
        };
        public static SelectList 사용자분류목록 = new SelectList(사용자분류, "ID", "Text");

        public static SelectList 검색유형목록 = new SelectList(
            new List<SelectListItemModel> { 
                new SelectListItemModel(BL사용자.검색_없음, "검색 없음"),
                new SelectListItemModel(BL사용자.검색_이름, "이름"),
                new SelectListItemModel(BL사용자.검색_로그인ID, "로그인ID"),
            },
            "ID", "Text"
        );

        public static 사용자 현재사용자
        {
            get
            {
                var user = (사용자)HttpContext.Current.Session[KEY_CURRENTUSER];
                if (user == null) {
                    int 사용자ID = 0;
                    int.TryParse(HttpContext.Current.User.Identity.Name, out 사용자ID);
                    if (사용자ID > 0) {
                        using (var db = new DBDataContext()) {
                            user = db.사용자.FirstOrDefault(p => p.ID == 사용자ID);
                            HttpContext.Current.Session[KEY_CURRENTUSER] = user;
                        }
                    }
                }
                return user ?? 손님;
            }
            set
            {
                HttpContext.Current.Session[KEY_CURRENTUSER] = value;
            }
        }

        public static string 현재사용자역할
        {
            get
            {
                if (Is로그인상태() == false) return BL사용자.GUEST;
                if (IsAdmin()) return BL사용자.ADMIN;
                if (IsStaff()) return BL사용자.STAFF;
                return BL사용자.USER;
            }
        }

        public static bool Is로그인상태()
        {
            return BL사용자.현재사용자 != null && BL사용자.현재사용자 != 손님;
        }

        public static bool IsAdmin()
        {
            return 현재사용자_역할확인(BL사용자.ADMIN);
        }

        public static bool IsStaff()
        {
            return 현재사용자_역할확인(BL사용자.STAFF);
        }

        public static bool IsAdminOrStaff()
        {
            return IsStaff() || IsAdmin();
        }

        private static bool 현재사용자_역할확인(string 역할)
        {
            int 사용자ID = 0;
            int.TryParse(HttpContext.Current.User.Identity.Name, out 사용자ID);
            if (사용자ID > 0) {
                var 목록 = (string[])HttpContext.Current.Session[KEY_CURRENTUSER_ROLES];
                if (목록 == null) {
                    using (var db = new DBDataContext()) {
                        var user = db.사용자.FirstOrDefault(p => p.ID == 사용자ID);
                        if (user == null) return false;
                        목록 = user.사용자_역할.Select(p => p.역할).ToArray();
                        HttpContext.Current.Session[KEY_CURRENTUSER_ROLES] = 목록;
                    }
                }
                return 목록.Any(p => p == 역할);
            }
            return false;
        }

        public static string 사용자역할(DB.사용자 data)
        {
            return data.사용자_역할.OrderBy(p => p.역할).Select(p => p.역할).FirstOrDefault() ?? USER;
        }

        // TODO: 세션 타임아웃 로그아웃도 구현하자
        public static void 로그아웃()
        {
            FormsAuthentication.SignOut();
            HttpContext.Current.Session[KEY_CURRENTUSER_ROLES] = null;
            HttpContext.Current.Session[KEY_CURRENTUSER] = null;
            BL로그기록.로그아웃_기록(BL사용자.현재사용자.ID);
            BL사용자.현재사용자 = null;
        }

        public static bool 로그인(string 로그인ID, string 비밀번호, string 리턴URL, out string 에러메시지)
        {
            사용자 user1 = null;
            에러메시지 = null;

            var 암호화된비밀번호 = CryptographyHelper.CookieEncrypt(비밀번호);
            using (var db = new DBDataContext()) {
                user1 = db.사용자.FirstOrDefault(p => p.로그인ID == 로그인ID);
                if (user1 != null && user1.비밀번호 == 암호화된비밀번호) 
                    return 로그인성공(user1);
            }

            using (var db1 = new SkhukisDBDataContext()) {
                var r1 = db1.COR_SKHUKB_LOGIN_SELECT('2', 로그인ID, 비밀번호).FirstOrDefault();
                if (r1 != null) {
                    var user2 = Forest사용자정보_로컬저장(로그인ID, 암호화된비밀번호, r1.StaffName, r1.Email); 
                    return 로그인성공(user2); 
                }

                var r2 = db1.COR_SKHUKB_LOGIN_SELECT('1', 로그인ID, null).FirstOrDefault();

                // 에러메시지 계산
                if (user1 == null && r2 == null)
                    에러메시지 = Consts.로그인ID오류;
                else
                    에러메시지 = Consts.비밀번호오류;
                BL로그기록.로그인실패_기록(로그인ID, 비밀번호, 리턴URL);
                return false;
            }
        }

        private static bool 로그인성공(사용자 user) {
            FormsAuthentication.SetAuthCookie(user.ID.ToString(), false);
            BL로그기록.로그인_기록(user.ID);
            BL사용자.현재사용자 = user;
            return true;
        }

        // forest 로부터 자동 로그인 요청
        public static bool 로그인(string 로그인ID, string 리턴URL, out string 에러메시지)
        {
            using (var db1 = new SkhukisDBDataContext()) {
                var r = db1.COR_SKHUKB_LOGIN_SELECT('1', 로그인ID, null).FirstOrDefault();
                if (r != null) {
                    var user = Forest사용자정보_로컬저장(로그인ID, "X", r.StaffName, r.Email);
                    FormsAuthentication.SetAuthCookie(user.ID.ToString(), false);
                    BL로그기록.로그인_기록(user.ID);
                    BL사용자.현재사용자 = user;
                    에러메시지 = null;
                    return true;
                }
                에러메시지 = Consts.로그인ID오류;
                BL로그기록.로그인실패_기록(로그인ID, "Forest Link", 리턴URL);
                return false;
            }
        }

        private static 사용자 Forest사용자정보_로컬저장(string 로그인ID, string 암호화된비밀번호, string 이름, string 이메일)
        {
            using (var db = new DBDataContext()) {
                var user = db.사용자.FirstOrDefault(p => p.로그인ID == 로그인ID);
                if (user == null) {
                    user = new 사용자 { 로그인ID = 로그인ID, 비밀번호 = 암호화된비밀번호, 이름 = 이름, 이메일 = 이메일 };
                    db.사용자.InsertOnSubmit(user);
                    BL로그기록.계정생성_기록(user.ID, user.로그인ID);
                    db.SubmitChanges();
                } else {
                    if (user.비밀번호 != 암호화된비밀번호) {
                        user.비밀번호 = 암호화된비밀번호;
                        db.SubmitChanges();
                    }
                }
                return user;
            }
        }

    }

    public static class UserLinkHekper
    {
        public static string UserList(this UrlHelper url, PaginationModel pagination)
        {
            if (url == null) new UserController().List(pagination: pagination);
            return url.Action("List", "User", pagination);
        }

        public static string UserListInit(this UrlHelper url)
        {
            if (url == null) new UserController().List(pagination: new PaginationModel());
            return url.Action("List", "User", PaginationModel.DEFAULT);
        }

        public static string UserListCategory(this UrlHelper url, int category)
        {
            if (url == null) new UserController().List(pagination: new PaginationModel());
            return url.Action("List", "User", new PaginationModel { page = 1, category = category });
        }

        public static string UserListResize(this UrlHelper url, int size)
        {
            if (url == null) new UserController().List(pagination: new PaginationModel());
            return url.Action("List", "User", new PaginationModel { page = 1, size = size });
        }

        public static string UserListSearch(this UrlHelper url, int srchType, string srchText)
        {
            if (url == null) new UserController().List(pagination: new PaginationModel());
            return url.Action("List", "User", new PaginationModel { page = 1, srchType = srchType, srchText = srchText });
        }
    }
}